<!--&lt;!&ndash;<template>&ndash;&gt;-->
<!--&lt;!&ndash;  <div class="goods-sku">&ndash;&gt;-->
<!--&lt;!&ndash;    <dl v-for="spec in specs" :key="spec.name">&ndash;&gt;-->
<!--&lt;!&ndash;      <dt>{{ spec.name }}</dt>&ndash;&gt;-->
<!--&lt;!&ndash;      <dd>&ndash;&gt;-->
<!--&lt;!&ndash;    <span&ndash;&gt;-->
<!--&lt;!&ndash;        v-for="value in spec.values"&ndash;&gt;-->
<!--&lt;!&ndash;        :key="value.name"&ndash;&gt;-->
<!--&lt;!&ndash;        :class="['sku', { selected: value.selected, disabled: value.disabled }]"&ndash;&gt;-->
<!--&lt;!&ndash;        @click="clickSpecs(spec, value)"&ndash;&gt;-->
<!--&lt;!&ndash;    >&ndash;&gt;-->
<!--&lt;!&ndash;      {{ value.name }}&ndash;&gt;-->
<!--&lt;!&ndash;    </span>&ndash;&gt;-->
<!--&lt;!&ndash;      </dd>&ndash;&gt;-->
<!--&lt;!&ndash;    </dl>&ndash;&gt;-->

<!--&lt;!&ndash;  </div>&ndash;&gt;-->
<!--&lt;!&ndash;  <pre>{{ specs }}</pre>&ndash;&gt;-->
<!--&lt;!&ndash;</template>&ndash;&gt;-->
<!--&lt;!&ndash;<script>&ndash;&gt;-->
<!--&lt;!&ndash;import { watchEffect,ref } from 'vue'&ndash;&gt;-->
<!--&lt;!&ndash;// import getPowerSet from '@/utils/power-set.js'&ndash;&gt;-->
<!--&lt;!&ndash;const spliter = '★'&ndash;&gt;-->



<!--&lt;!&ndash;export const getPathMap = (skus) => {&ndash;&gt;-->
<!--&lt;!&ndash;  const pathMap = new Map()&ndash;&gt;-->
<!--&lt;!&ndash;  skus?.forEach(sku => {&ndash;&gt;-->
<!--&lt;!&ndash;    if (sku.inventory <= 0) return&ndash;&gt;-->
<!--&lt;!&ndash;    try {&ndash;&gt;-->
<!--&lt;!&ndash;      const specObj = JSON.parse(sku.specs)&ndash;&gt;-->
<!--&lt;!&ndash;      const path = Object.values(specObj).join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;      console.log('✅ 有效 SKU path:', path)  // 添加这个&ndash;&gt;-->
<!--&lt;!&ndash;      pathMap.set(path, sku)&ndash;&gt;-->
<!--&lt;!&ndash;    } catch (e) {&ndash;&gt;-->
<!--&lt;!&ndash;      console.warn('规格解析失败', sku.specs)&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->
<!--&lt;!&ndash;  })&ndash;&gt;-->
<!--&lt;!&ndash;  return pathMap&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->

<!--&lt;!&ndash;// 初始化禁用状态&ndash;&gt;-->
<!--&lt;!&ndash;export const initDisabledStatus = (specs, pathMap) => {&ndash;&gt;-->
<!--&lt;!&ndash;  specs.forEach(spec => {&ndash;&gt;-->
<!--&lt;!&ndash;    spec.values.forEach(value => {&ndash;&gt;-->
<!--&lt;!&ndash;      const tempSpecs = specs.map(s => {&ndash;&gt;-->
<!--&lt;!&ndash;        if (s.name === spec.name) return value.name&ndash;&gt;-->
<!--&lt;!&ndash;        const selected = s.values.find(v => v.selected)&ndash;&gt;-->
<!--&lt;!&ndash;        return selected?.name || ''&ndash;&gt;-->
<!--&lt;!&ndash;      })&ndash;&gt;-->
<!--&lt;!&ndash;      const path = tempSpecs.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;      value.disabled = !pathMap.has(path)&ndash;&gt;-->
<!--&lt;!&ndash;    })&ndash;&gt;-->
<!--&lt;!&ndash;  })&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->


<!--&lt;!&ndash;// 更新禁用状态（某项点击后）&ndash;&gt;-->
<!--&lt;!&ndash;const updateDisabledStatus = (specs, pathMap) => {&ndash;&gt;-->
<!--&lt;!&ndash;  specs.forEach((spec, i) => {&ndash;&gt;-->
<!--&lt;!&ndash;    const selectedArr = specs.map(s => s.values.find(v => v.selected)?.name || '')&ndash;&gt;-->
<!--&lt;!&ndash;    spec.values.forEach(val => {&ndash;&gt;-->
<!--&lt;!&ndash;      if (!val.selected) {&ndash;&gt;-->
<!--&lt;!&ndash;        const tempSelected = [...selectedArr]&ndash;&gt;-->
<!--&lt;!&ndash;        tempSelected[i] = val.name&ndash;&gt;-->
<!--&lt;!&ndash;        const key = tempSelected.join(spliter) // 不要 filter！&ndash;&gt;-->
<!--&lt;!&ndash;        val.disabled = !pathMap.has(key)&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->
<!--&lt;!&ndash;    })&ndash;&gt;-->
<!--&lt;!&ndash;  })&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->
<!--&lt;!&ndash;export const buildSpecsFromSkus = (skus) => {&ndash;&gt;-->
<!--&lt;!&ndash;  const specMap = new Map()&ndash;&gt;-->

<!--&lt;!&ndash;  skus?.forEach(sku => {&ndash;&gt;-->
<!--&lt;!&ndash;    if (!sku.specs) return&ndash;&gt;-->
<!--&lt;!&ndash;    let specObj&ndash;&gt;-->
<!--&lt;!&ndash;    try {&ndash;&gt;-->
<!--&lt;!&ndash;      specObj = JSON.parse(sku.specs)&ndash;&gt;-->
<!--&lt;!&ndash;    } catch {&ndash;&gt;-->
<!--&lt;!&ndash;      return&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->

<!--&lt;!&ndash;    for (const [key, value] of Object.entries(specObj)) {&ndash;&gt;-->
<!--&lt;!&ndash;      if (!specMap.has(key)) specMap.set(key, new Set())&ndash;&gt;-->
<!--&lt;!&ndash;      specMap.get(key).add(value)&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->
<!--&lt;!&ndash;  })&ndash;&gt;-->

<!--&lt;!&ndash;  // 转换为结构 [{ name: '颜色', values: [{ name: '红色', ... }] }]&ndash;&gt;-->
<!--&lt;!&ndash;  const specs = []&ndash;&gt;-->
<!--&lt;!&ndash;  for (const [name, valueSet] of specMap.entries()) {&ndash;&gt;-->
<!--&lt;!&ndash;    specs.push({&ndash;&gt;-->
<!--&lt;!&ndash;      name,&ndash;&gt;-->
<!--&lt;!&ndash;      values: [...valueSet].map(v => ({&ndash;&gt;-->
<!--&lt;!&ndash;        name: v,&ndash;&gt;-->
<!--&lt;!&ndash;        selected: false,&ndash;&gt;-->
<!--&lt;!&ndash;        disabled: false&ndash;&gt;-->
<!--&lt;!&ndash;      }))&ndash;&gt;-->
<!--&lt;!&ndash;    })&ndash;&gt;-->
<!--&lt;!&ndash;  }&ndash;&gt;-->

<!--&lt;!&ndash;  return specs&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->

<!--&lt;!&ndash;export default {&ndash;&gt;-->
<!--&lt;!&ndash;  name: 'GoodsSku',&ndash;&gt;-->
<!--&lt;!&ndash;  props: {&ndash;&gt;-->
<!--&lt;!&ndash;    goods: {&ndash;&gt;-->
<!--&lt;!&ndash;      type: Object,&ndash;&gt;-->
<!--&lt;!&ndash;      default: () => ({ specs: [], skus: [] })&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->
<!--&lt;!&ndash;  },&ndash;&gt;-->
<!--&lt;!&ndash;  emits: ['change'],&ndash;&gt;-->
<!--&lt;!&ndash;  setup(props, { emit }) {&ndash;&gt;-->
<!--&lt;!&ndash;    let pathMap = new Map()&ndash;&gt;-->
<!--&lt;!&ndash;    const specs = ref([])&ndash;&gt;-->
<!--&lt;!&ndash;    // watchEffect(() => {&ndash;&gt;-->
<!--&lt;!&ndash;    //   // specs.value = buildSpecsFromSkus(props.goods.skus)&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 默认选中每组中第一个合法组合的选项&ndash;&gt;-->
<!--&lt;!&ndash;    //   specs.value.forEach((spec, i) => {&ndash;&gt;-->
<!--&lt;!&ndash;    //     for (const val of spec.values) {&ndash;&gt;-->
<!--&lt;!&ndash;    //       const tempSpecs = specs.value.map((s, j) => {&ndash;&gt;-->
<!--&lt;!&ndash;    //         if (i === j) return val.name&ndash;&gt;-->
<!--&lt;!&ndash;    //         const selected = s.values.find(v => v.selected)&ndash;&gt;-->
<!--&lt;!&ndash;    //         return selected?.name || ''&ndash;&gt;-->
<!--&lt;!&ndash;    //       })&ndash;&gt;-->
<!--&lt;!&ndash;    //       const path = tempSpecs.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;    //       if (pathMap.has(path)) {&ndash;&gt;-->
<!--&lt;!&ndash;    //         val.selected = true&ndash;&gt;-->
<!--&lt;!&ndash;    //         break&ndash;&gt;-->
<!--&lt;!&ndash;    //       }&ndash;&gt;-->
<!--&lt;!&ndash;    //     }&ndash;&gt;-->
<!--&lt;!&ndash;    //   });&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   pathMap = getPathMap(props.goods.skus)&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 默认选中：如果某一组只有一个可选项，则选中&ndash;&gt;-->
<!--&lt;!&ndash;    //   // specs.value.forEach(spec => {&ndash;&gt;-->
<!--&lt;!&ndash;    //   //   const allValues = spec.values&ndash;&gt;-->
<!--&lt;!&ndash;    //   //   if (allValues.length === 1) {&ndash;&gt;-->
<!--&lt;!&ndash;    //   //     allValues[0].selected = true&ndash;&gt;-->
<!--&lt;!&ndash;    //   //   }&ndash;&gt;-->
<!--&lt;!&ndash;    //   // })&ndash;&gt;-->
<!--&lt;!&ndash;    //   specs.value.forEach(spec => {&ndash;&gt;-->
<!--&lt;!&ndash;    //     // 优先选择第一个不禁用的选项&ndash;&gt;-->
<!--&lt;!&ndash;    //     const firstAvailable = spec.values.find(v => {&ndash;&gt;-->
<!--&lt;!&ndash;    //       const tempSpecs = specs.value.map(s => {&ndash;&gt;-->
<!--&lt;!&ndash;    //         if (s.name === spec.name) return v.name&ndash;&gt;-->
<!--&lt;!&ndash;    //         const selected = s.values.find(val => val.selected)&ndash;&gt;-->
<!--&lt;!&ndash;    //         return selected?.name || ''&ndash;&gt;-->
<!--&lt;!&ndash;    //       })&ndash;&gt;-->
<!--&lt;!&ndash;    //       const path = tempSpecs.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;    //       return pathMap.has(path)&ndash;&gt;-->
<!--&lt;!&ndash;    //     })&ndash;&gt;-->
<!--&lt;!&ndash;    //     if (firstAvailable) {&ndash;&gt;-->
<!--&lt;!&ndash;    //       firstAvailable.selected = true&ndash;&gt;-->
<!--&lt;!&ndash;    //     }&ndash;&gt;-->
<!--&lt;!&ndash;    //   })&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 再初始化禁用状态（此时已知哪些项选中）&ndash;&gt;-->
<!--&lt;!&ndash;    //   initDisabledStatus(specs.value, pathMap)&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 如果选中完整，则发出 SKU 变更&ndash;&gt;-->
<!--&lt;!&ndash;    //   const selected = specs.value.map(s =>&ndash;&gt;-->
<!--&lt;!&ndash;    //       s.values.find(v => v.selected)?.name&ndash;&gt;-->
<!--&lt;!&ndash;    //   )&ndash;&gt;-->
<!--&lt;!&ndash;    //   if (selected.every(Boolean)) {&ndash;&gt;-->
<!--&lt;!&ndash;    //     const key = selected.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;    //     const matched = pathMap.get(key)&ndash;&gt;-->
<!--&lt;!&ndash;    //     if (matched) {&ndash;&gt;-->
<!--&lt;!&ndash;    //       emit('change', {&ndash;&gt;-->
<!--&lt;!&ndash;    //         skuId: matched.id,&ndash;&gt;-->
<!--&lt;!&ndash;    //         price: matched.price,&ndash;&gt;-->
<!--&lt;!&ndash;    //         specsText: selected.join(' '),&ndash;&gt;-->
<!--&lt;!&ndash;    //         inventory: matched.inventory&ndash;&gt;-->
<!--&lt;!&ndash;    //       })&ndash;&gt;-->
<!--&lt;!&ndash;    //     }&ndash;&gt;-->
<!--&lt;!&ndash;    //   }&ndash;&gt;-->
<!--&lt;!&ndash;    // })&ndash;&gt;-->
<!--&lt;!&ndash;    // watchEffect(() => {&ndash;&gt;-->
<!--&lt;!&ndash;    //   specs.value = buildSpecsFromSkus(props.goods.skus)&ndash;&gt;-->
<!--&lt;!&ndash;    //   pathMap = getPathMap(props.goods.skus)&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 默认选中每组中第一个合法组合的选项&ndash;&gt;-->
<!--&lt;!&ndash;    //   specs.value.forEach((spec, i) => {&ndash;&gt;-->
<!--&lt;!&ndash;    //     for (const val of spec.values) {&ndash;&gt;-->
<!--&lt;!&ndash;    //       const tempSpecs = specs.value.map((s, j) => {&ndash;&gt;-->
<!--&lt;!&ndash;    //         if (i === j) return val.name&ndash;&gt;-->
<!--&lt;!&ndash;    //         const selected = s.values.find(v => v.selected)&ndash;&gt;-->
<!--&lt;!&ndash;    //         return selected?.name || ''&ndash;&gt;-->
<!--&lt;!&ndash;    //       })&ndash;&gt;-->
<!--&lt;!&ndash;    //       const path = tempSpecs.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;    //       if (pathMap.has(path)) {&ndash;&gt;-->
<!--&lt;!&ndash;    //         val.selected = true&ndash;&gt;-->
<!--&lt;!&ndash;    //         break&ndash;&gt;-->
<!--&lt;!&ndash;    //       }&ndash;&gt;-->
<!--&lt;!&ndash;    //     }&ndash;&gt;-->
<!--&lt;!&ndash;    //   })&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 初始化禁用状态&ndash;&gt;-->
<!--&lt;!&ndash;    //   initDisabledStatus(specs.value, pathMap)&ndash;&gt;-->
<!--&lt;!&ndash;    //&ndash;&gt;-->
<!--&lt;!&ndash;    //   // 如果选中完整，则发出 SKU 变更&ndash;&gt;-->
<!--&lt;!&ndash;    //   const selected = specs.value.map(s =>&ndash;&gt;-->
<!--&lt;!&ndash;    //       s.values.find(v => v.selected)?.name&ndash;&gt;-->
<!--&lt;!&ndash;    //   )&ndash;&gt;-->
<!--&lt;!&ndash;    //   if (selected.every(Boolean)) {&ndash;&gt;-->
<!--&lt;!&ndash;    //     const key = selected.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;    //     const matched = pathMap.get(key)&ndash;&gt;-->
<!--&lt;!&ndash;    //     if (matched) {&ndash;&gt;-->
<!--&lt;!&ndash;    //       emit('change', {&ndash;&gt;-->
<!--&lt;!&ndash;    //         skuId: matched.id,&ndash;&gt;-->
<!--&lt;!&ndash;    //         price: matched.price,&ndash;&gt;-->
<!--&lt;!&ndash;    //         specsText: selected.join(' '),&ndash;&gt;-->
<!--&lt;!&ndash;    //         inventory: matched.inventory&ndash;&gt;-->
<!--&lt;!&ndash;    //       })&ndash;&gt;-->
<!--&lt;!&ndash;    //     }&ndash;&gt;-->
<!--&lt;!&ndash;    //   }&ndash;&gt;-->
<!--&lt;!&ndash;    // })&ndash;&gt;-->

<!--&lt;!&ndash;    watchEffect(() => {&ndash;&gt;-->
<!--&lt;!&ndash;      const rawSpecs = buildSpecsFromSkus(props.goods.skus)&ndash;&gt;-->
<!--&lt;!&ndash;      pathMap = getPathMap(props.goods.skus)&ndash;&gt;-->

<!--&lt;!&ndash;      // 提前设置选中项：每组选第一个合法选项&ndash;&gt;-->
<!--&lt;!&ndash;      rawSpecs.forEach((spec, i) => {&ndash;&gt;-->
<!--&lt;!&ndash;        for (const val of spec.values) {&ndash;&gt;-->
<!--&lt;!&ndash;          const temp = rawSpecs.map((s, j) => {&ndash;&gt;-->
<!--&lt;!&ndash;            if (i === j) return val.name&ndash;&gt;-->
<!--&lt;!&ndash;            const selected = s.values.find(v => v.selected)&ndash;&gt;-->
<!--&lt;!&ndash;            return selected?.name || ''&ndash;&gt;-->
<!--&lt;!&ndash;          })&ndash;&gt;-->
<!--&lt;!&ndash;          const path = temp.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;          if (pathMap.has(path)) {&ndash;&gt;-->
<!--&lt;!&ndash;            val.selected = true&ndash;&gt;-->
<!--&lt;!&ndash;            break&ndash;&gt;-->
<!--&lt;!&ndash;          }&ndash;&gt;-->
<!--&lt;!&ndash;        }&ndash;&gt;-->
<!--&lt;!&ndash;      })&ndash;&gt;-->

<!--&lt;!&ndash;      // 设置最终 specs&ndash;&gt;-->
<!--&lt;!&ndash;      specs.value = rawSpecs&ndash;&gt;-->

<!--&lt;!&ndash;      // 初始化禁用状态&ndash;&gt;-->
<!--&lt;!&ndash;      initDisabledStatus(specs.value, pathMap)&ndash;&gt;-->

<!--&lt;!&ndash;      // 发出 SKU 变更&ndash;&gt;-->
<!--&lt;!&ndash;      const selected = specs.value.map(s => s.values.find(v => v.selected)?.name)&ndash;&gt;-->
<!--&lt;!&ndash;      if (selected.every(Boolean)) {&ndash;&gt;-->
<!--&lt;!&ndash;        const key = selected.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;        const matched = pathMap.get(key)&ndash;&gt;-->
<!--&lt;!&ndash;        if (matched) {&ndash;&gt;-->
<!--&lt;!&ndash;          emit('change', {&ndash;&gt;-->
<!--&lt;!&ndash;            skuId: matched.id,&ndash;&gt;-->
<!--&lt;!&ndash;            price: matched.price,&ndash;&gt;-->
<!--&lt;!&ndash;            specsText: selected.join(' '),&ndash;&gt;-->
<!--&lt;!&ndash;            inventory: matched.inventory&ndash;&gt;-->
<!--&lt;!&ndash;          })&ndash;&gt;-->
<!--&lt;!&ndash;        }&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->
<!--&lt;!&ndash;    })&ndash;&gt;-->

<!--&lt;!&ndash;    // 替换点击逻辑为：&ndash;&gt;-->
<!--&lt;!&ndash;    const clickSpecs = (spec, val) => {&ndash;&gt;-->
<!--&lt;!&ndash;      if (val.disabled) return&ndash;&gt;-->

<!--&lt;!&ndash;      const wasSelected = val.selected&ndash;&gt;-->

<!--&lt;!&ndash;      // 创建新的 specs 结构&ndash;&gt;-->
<!--&lt;!&ndash;      specs.value = specs.value.map(s => {&ndash;&gt;-->
<!--&lt;!&ndash;        if (s.name === spec.name) {&ndash;&gt;-->
<!--&lt;!&ndash;          return {&ndash;&gt;-->
<!--&lt;!&ndash;            ...s,&ndash;&gt;-->
<!--&lt;!&ndash;            values: s.values.map(v => ({&ndash;&gt;-->
<!--&lt;!&ndash;              ...v,&ndash;&gt;-->
<!--&lt;!&ndash;              selected: v.name === val.name ? !wasSelected : false&ndash;&gt;-->
<!--&lt;!&ndash;            }))&ndash;&gt;-->
<!--&lt;!&ndash;          }&ndash;&gt;-->
<!--&lt;!&ndash;        } else {&ndash;&gt;-->
<!--&lt;!&ndash;          return s&ndash;&gt;-->
<!--&lt;!&ndash;        }&ndash;&gt;-->
<!--&lt;!&ndash;      })&ndash;&gt;-->

<!--&lt;!&ndash;      // 更新禁用状态&ndash;&gt;-->
<!--&lt;!&ndash;      updateDisabledStatus(specs.value, pathMap)&ndash;&gt;-->

<!--&lt;!&ndash;      // 获取选中项&ndash;&gt;-->
<!--&lt;!&ndash;      const selected = specs.value.map(s =>&ndash;&gt;-->
<!--&lt;!&ndash;          s.values.find(v => v.selected)?.name&ndash;&gt;-->
<!--&lt;!&ndash;      )&ndash;&gt;-->

<!--&lt;!&ndash;      if (selected.every(Boolean)) {&ndash;&gt;-->
<!--&lt;!&ndash;        const key = selected.join(spliter)&ndash;&gt;-->
<!--&lt;!&ndash;        const matched = pathMap.get(key)&ndash;&gt;-->
<!--&lt;!&ndash;        if (matched) {&ndash;&gt;-->
<!--&lt;!&ndash;          emit('change', {&ndash;&gt;-->
<!--&lt;!&ndash;            skuId: matched.id,&ndash;&gt;-->
<!--&lt;!&ndash;            price: matched.price,&ndash;&gt;-->
<!--&lt;!&ndash;            specsText: selected.join(' '),&ndash;&gt;-->
<!--&lt;!&ndash;            inventory: matched.inventory&ndash;&gt;-->
<!--&lt;!&ndash;          })&ndash;&gt;-->
<!--&lt;!&ndash;        } else {&ndash;&gt;-->
<!--&lt;!&ndash;          emit('change', {})&ndash;&gt;-->
<!--&lt;!&ndash;        }&ndash;&gt;-->
<!--&lt;!&ndash;      } else {&ndash;&gt;-->
<!--&lt;!&ndash;        emit('change', {})&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->

<!--&lt;!&ndash;    return { clickSpecs,specs }&ndash;&gt;-->

<!--&lt;!&ndash;  }&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->

<!--&lt;!&ndash;</script>&ndash;&gt;-->

<!--&lt;!&ndash;<style scoped lang="scss">&ndash;&gt;-->
<!--&lt;!&ndash;@mixin sku-state-mixin {&ndash;&gt;-->
<!--&lt;!&ndash;  border: 1px solid #e4e4e4;&ndash;&gt;-->
<!--&lt;!&ndash;  margin-right: 10px;&ndash;&gt;-->
<!--&lt;!&ndash;  cursor: pointer;&ndash;&gt;-->

<!--&lt;!&ndash;  &.selected {&ndash;&gt;-->
<!--&lt;!&ndash;    border-color: $xtxColor;&ndash;&gt;-->
<!--&lt;!&ndash;  }&ndash;&gt;-->

<!--&lt;!&ndash;  &.disabled {&ndash;&gt;-->
<!--&lt;!&ndash;    opacity: 0.6;&ndash;&gt;-->
<!--&lt;!&ndash;    border-style: dashed;&ndash;&gt;-->
<!--&lt;!&ndash;    cursor: not-allowed;&ndash;&gt;-->
<!--&lt;!&ndash;  }&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->

<!--&lt;!&ndash;.goods-sku {&ndash;&gt;-->
<!--&lt;!&ndash;  @media (max-width: 768px) {&ndash;&gt;-->
<!--&lt;!&ndash;    dl {&ndash;&gt;-->
<!--&lt;!&ndash;      flex-direction: column;&ndash;&gt;-->
<!--&lt;!&ndash;      align-items: flex-start;&ndash;&gt;-->

<!--&lt;!&ndash;      dt {&ndash;&gt;-->
<!--&lt;!&ndash;        margin-bottom: 8px;&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->
<!--&lt;!&ndash;  }&ndash;&gt;-->
<!--&lt;!&ndash;  padding-left: 10px;&ndash;&gt;-->
<!--&lt;!&ndash;  padding-top: 20px;&ndash;&gt;-->

<!--&lt;!&ndash;  dl {&ndash;&gt;-->
<!--&lt;!&ndash;    display: flex;&ndash;&gt;-->
<!--&lt;!&ndash;    padding-bottom: 20px;&ndash;&gt;-->
<!--&lt;!&ndash;    align-items: center;&ndash;&gt;-->

<!--&lt;!&ndash;    dt {&ndash;&gt;-->
<!--&lt;!&ndash;      width: 50px;&ndash;&gt;-->
<!--&lt;!&ndash;      color: #999;&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->

<!--&lt;!&ndash;    dd {&ndash;&gt;-->
<!--&lt;!&ndash;      flex: 1;&ndash;&gt;-->
<!--&lt;!&ndash;      color: #666;&ndash;&gt;-->

<!--&lt;!&ndash;      > img {&ndash;&gt;-->
<!--&lt;!&ndash;        width: 50px;&ndash;&gt;-->
<!--&lt;!&ndash;        height: 50px;&ndash;&gt;-->
<!--&lt;!&ndash;        margin-bottom: 4px;&ndash;&gt;-->
<!--&lt;!&ndash;        @include sku-state-mixin;&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->

<!--&lt;!&ndash;      > span {&ndash;&gt;-->
<!--&lt;!&ndash;        display: inline-block;&ndash;&gt;-->
<!--&lt;!&ndash;        height: 30px;&ndash;&gt;-->
<!--&lt;!&ndash;        line-height: 28px;&ndash;&gt;-->
<!--&lt;!&ndash;        padding: 0 20px;&ndash;&gt;-->
<!--&lt;!&ndash;        margin-bottom: 4px;&ndash;&gt;-->
<!--&lt;!&ndash;        @include sku-state-mixin;&ndash;&gt;-->
<!--&lt;!&ndash;      }&ndash;&gt;-->
<!--&lt;!&ndash;    }&ndash;&gt;-->
<!--&lt;!&ndash;  }&ndash;&gt;-->
<!--&lt;!&ndash;}&ndash;&gt;-->
<!--&lt;!&ndash;</style>&ndash;&gt;-->

<!--<template>-->
<!--  <div class="goods-sku">-->
<!--    <dl v-for="spec in specs" :key="spec.name">-->
<!--      <dt>{{ spec.name }}</dt>-->
<!--      <dd>-->
<!--        <span-->
<!--            v-for="value in spec.values"-->
<!--            :key="value.name"-->
<!--            :class="['sku', { selected: value.selected, disabled: value.disabled }]"-->
<!--            @click="clickSpecs(spec, value)"-->
<!--        >-->
<!--          {{ value.name }}-->
<!--        </span>-->
<!--      </dd>-->
<!--    </dl>-->
<!--  </div>-->
<!--  <pre>{{ specs }}</pre>-->
<!--</template>-->

<!--<script>-->
<!--import { watchEffect, ref } from 'vue'-->
<!--const spliter = '★'-->

<!--// 获取路径映射-->
<!--// export const getPathMap = (skus) => {-->
<!--//   const pathMap = new Map()-->
<!--//   skus?.forEach(sku => {-->
<!--//     if (sku.inventory <= 0) return-->
<!--//     try {-->
<!--//       const specObj = JSON.parse(sku.specs)-->
<!--//       const path = Object.values(specObj).join(spliter)-->
<!--//       console.log('✅ 有效 SKU path:', path)  // 打印有效的 SKU 路径-->
<!--//       pathMap.set(path, sku)-->
<!--//     } catch (e) {-->
<!--//       console.warn('规格解析失败', sku.specs)-->
<!--//     }-->
<!--//   })-->
<!--//   return pathMap-->
<!--// }-->

<!--export const getPathMap = (skus) => {-->
<!--  const pathMap = new Map()-->
<!--  console.log('SKUs:', skus) // 打印原始SKU数据-->
<!--  skus?.forEach(sku => {-->
<!--    if (sku.inventory <= 0) {-->
<!--      console.log('跳过库存为0的SKU:', sku.id)-->
<!--      return-->
<!--    }-->
<!--    try {-->
<!--      const specObj = JSON.parse(sku.specs)-->
<!--      const path = Object.values(specObj).join(spliter)-->
<!--      console.log('✅ 有效 SKU path:', path, '对应SKU:', sku.id)-->
<!--      pathMap.set(path, sku)-->
<!--    } catch (e) {-->
<!--      console.error('❌ 规格解析失败', sku.specs, '错误:', e)-->
<!--    }-->
<!--  })-->
<!--  return pathMap-->
<!--}-->
<!--// 初始化禁用状态-->
<!--// export const initDisabledStatus = (specs, pathMap) => {-->
<!--//   specs.forEach(spec => {-->
<!--//     spec.values.forEach(value => {-->
<!--//       const tempSpecs = specs.map(s => {-->
<!--//         if (s.name === spec.name) return value.name-->
<!--//         const selected = s.values.find(v => v.selected)-->
<!--//         return selected?.name || ''-->
<!--//       })-->
<!--//       const path = tempSpecs.join(spliter)-->
<!--//       value.disabled = !pathMap.has(path)-->
<!--//     })-->
<!--//   })-->
<!--// }-->
<!--export const initDisabledStatus = (specs, pathMap) => {-->
<!--  specs.forEach(spec => {-->
<!--    spec.values.forEach(value => {-->
<!--      // 生成临时路径时，未选中的规格用空字符串占位-->
<!--      const tempSpecs = specs.map(s => {-->
<!--        if (s.name === spec.name) return value.name-->
<!--        const selected = s.values.find(v => v.selected)-->
<!--        return selected?.name || '' // 未选中的规格留空-->
<!--      })-->
<!--      const path = tempSpecs.join(spliter)-->
<!--      // 检查路径是否有效（允许部分选中）-->
<!--      const isValid = Array.from(pathMap.keys()).some(key =>-->
<!--          key.startsWith(path + spliter) ||-->
<!--          key.includes(spliter + path) ||-->
<!--          key === path-->
<!--      )-->
<!--      value.disabled = !isValid-->
<!--    })-->
<!--  })-->
<!--}-->
<!--// 更新禁用状态（某项点击后）-->
<!--// const updateDisabledStatus = (specs, pathMap) => {-->
<!--//   specs.forEach((spec, i) => {-->
<!--//     const selectedArr = specs.map(s => s.values.find(v => v.selected)?.name || '')-->
<!--//     spec.values.forEach(val => {-->
<!--//       if (!val.selected) {-->
<!--//         const tempSelected = [...selectedArr]-->
<!--//         tempSelected[i] = val.name-->
<!--//         const key = tempSelected.join(spliter)-->
<!--//         val.disabled = !pathMap.has(key)-->
<!--//       }-->
<!--//     })-->
<!--//   })-->
<!--// }-->
<!--// GoodsSku.vue-->
<!--const updateDisabledStatus = (specs, pathMap) => {-->

<!--  specs.forEach((spec, i) => {-->
<!--    // ✅ 获取当前所有选中项（空字符串表示未选）-->
<!--    const selectedArr = specs.map(s => {-->
<!--      const selectedVal = s.values.find(v => v.selected)-->
<!--      return selectedVal ? selectedVal.name : ''-->
<!--    })-->

<!--    spec.values.forEach(val => {-->
<!--      if (val.selected) {-->
<!--        val.disabled = false // 已选中项永不禁用-->
<!--        return-->
<!--      }-->

<!--      // ✅ 生成临时路径时保留已选项-->
<!--      const tempSelected = [...selectedArr]-->
<!--      tempSelected[i] = val.name-->
<!--      const key = tempSelected.join(spliter)-->

<!--      // ✅ 允许部分匹配（如 "蓝色" 匹配 "蓝色★XL"）-->
<!--      val.disabled = !Array.from(pathMap.keys()).some(k =>-->
<!--          k.startsWith(key) ||-->
<!--          k.includes(spliter + key) ||-->
<!--          k === key-->
<!--      )-->
<!--    })-->
<!--  })-->
<!--}-->
<!--// 从 SKU 数据中构建规格信息-->
<!--export const buildSpecsFromSkus = (skus) => {-->
<!--  const specMap = new Map()-->

<!--  skus?.forEach(sku => {-->
<!--    if (!sku.specs) return-->
<!--    let specObj-->
<!--    try {-->
<!--      specObj = JSON.parse(sku.specs)-->
<!--    } catch {-->
<!--      return-->
<!--    }-->

<!--    for (const [key, value] of Object.entries(specObj)) {-->
<!--      if (!specMap.has(key)) specMap.set(key, new Set())-->
<!--      specMap.get(key).add(value)-->
<!--    }-->
<!--  })-->

<!--  const specs = []-->
<!--  for (const [name, valueSet] of specMap.entries()) {-->
<!--    specs.push({-->
<!--      name,-->
<!--      values: [...valueSet].map(v => ({-->
<!--        name: v,-->
<!--        selected: false,-->
<!--        disabled: false-->
<!--      }))-->
<!--    })-->
<!--  }-->

<!--  return specs-->
<!--}-->

<!--export default {-->
<!--  name: 'GoodsSku',-->
<!--  props: {-->
<!--    goods: {-->
<!--      type: Object,-->
<!--      default: () => ({ specs: [], skus: [] })-->
<!--    }-->
<!--  },-->
<!--  emits: ['change'],-->
<!--  setup(props, { emit }) {-->
<!--    let pathMap = new Map()-->
<!--    const specs = ref([])-->
<!--    let isUpdating = false // 添加状态锁-->
<!--    // 监听商品数据变化并更新规格-->
<!--    watchEffect(() => {-->
<!--      if (isUpdating) return-->
<!--      isUpdating = true-->
<!--      const rawSpecs = buildSpecsFromSkus(props.goods.skus)-->
<!--      pathMap = getPathMap(props.goods.skus)-->

<!--      // 优化默认选中逻辑：每组选第一个有效选项-->
<!--      rawSpecs.forEach((spec, i) => {-->
<!--        const firstValidValue = spec.values.find(val => {-->
<!--          const temp = rawSpecs.map((s, j) => {-->
<!--            if (i === j) return val.name-->
<!--            // 其他规格优先使用已选值，否则尝试第一个有效值-->
<!--            const selected = s.values.find(v => v.selected)-->
<!--            return selected?.name || s.values[0]?.name || ''-->
<!--          })-->
<!--          return pathMap.has(temp.join(spliter))-->
<!--        })-->
<!--        if (firstValidValue) {-->
<!--          firstValidValue.selected = true-->
<!--        }-->
<!--      })-->

<!--      // 设置最终 specs-->
<!--      specs.value = rawSpecs-->

<!--      // 初始化禁用状态-->
<!--      initDisabledStatus(specs.value, pathMap)-->

<!--      // 发出 SKU 变更-->
<!--      const selected = specs.value.map(s => s.values.find(v => v.selected)?.name)-->
<!--      if (selected.every(Boolean)) {-->
<!--        const key = selected.join(spliter)-->
<!--        const matched = pathMap.get(key)-->
<!--        if (matched) {-->
<!--          emit('change', {-->
<!--            skuId: matched.id,-->
<!--            price: matched.price,-->
<!--            specsText: selected.join(' '),-->
<!--            inventory: matched.inventory-->
<!--          })-->
<!--        }-->
<!--      }-->
<!--      isUpdating = false-->
<!--    })-->

<!--    // 点击规格选项的处理逻辑-->
<!--    // const clickSpecs = (spec, val) => {-->
<!--    //   if (val.disabled) return-->
<!--    //-->
<!--    //   // 使用深拷贝触发响应式更新-->
<!--    //   const newSpecs = JSON.parse(JSON.stringify(specs.value))-->
<!--    //   const targetSpec = newSpecs.find(s => s.name === spec.name)-->
<!--    //   const targetValue = targetSpec.values.find(v => v.name === val.name)-->
<!--    //-->
<!--    //   // 切换选中状态-->
<!--    //   targetSpec.values.forEach(v => {-->
<!--    //     v.selected = (v.name === targetValue.name) ? !targetValue.selected : false-->
<!--    //   })-->
<!--    //-->
<!--    //   specs.value = newSpecs // 触发响应式更新-->
<!--    //-->
<!--    //   // 更新禁用状态-->
<!--    //   updateDisabledStatus(specs.value, pathMap)-->
<!--    //-->
<!--    //   // 获取选中项-->
<!--    //   const selected = specs.value.map(s =>-->
<!--    //       s.values.find(v => v.selected)?.name-->
<!--    //   )-->
<!--    //-->
<!--    //   if (selected.every(Boolean)) {-->
<!--    //     const key = selected.join(spliter)-->
<!--    //     const matched = pathMap.get(key)-->
<!--    //     if (matched) {-->
<!--    //       emit('change', {-->
<!--    //         skuId: matched.id,-->
<!--    //         price: matched.price,-->
<!--    //         specsText: selected.join(' '),-->
<!--    //         inventory: matched.inventory-->
<!--    //       })-->
<!--    //     } else {-->
<!--    //       emit('change', {})-->
<!--    //     }-->
<!--    //   } else {-->
<!--    //     emit('change', {})-->
<!--    //   }-->
<!--    // }-->
<!--// GoodsSku.vue-->
<!--    const clickSpecs = (spec, val) => {-->
<!--      console.log('👉 点击:', spec.name, val.name, '原状态:', val.selected)-->
<!--      if (val.disabled) return-->

<!--      // ✅ 创建新对象触发响应式更新-->
<!--      const newSpecs = specs.value.map(s => {-->
<!--        if (s.name === spec.name) {-->
<!--          return {-->
<!--            ...s,-->
<!--            values: s.values.map(v => ({-->
<!--              ...v,-->
<!--              selected: v.name === val.name ? !v.selected : false-->
<!--            }))-->
<!--          }-->
<!--        }-->
<!--        return { ...s } // 确保外层对象也更新-->
<!--      })-->

<!--      specs.value = newSpecs // 触发响应式更新-->
<!--      updateDisabledStatus(specs.value, pathMap)-->

<!--      // ✅ 立即触发事件-->
<!--      const selected = newSpecs.map(s => s.values.find(v => v.selected)?.name)-->
<!--      if (selected.every(Boolean)) {-->
<!--        const key = selected.join(spliter)-->
<!--        emit('change', pathMap.get(key))-->
<!--      } else {-->
<!--        emit('change', null)-->
<!--      }-->
<!--      console.log('🔄 新状态:', newSpecs)-->
<!--    }-->
<!--    return { clickSpecs, specs }-->
<!--  }-->
<!--}-->
<!--</script>-->

<!--<style scoped lang="scss">-->
<!--@mixin sku-state-mixin {-->
<!--  border: 1px solid #e4e4e4;-->
<!--  margin-right: 10px;-->
<!--  cursor: pointer;-->

<!--  &.selected {-->
<!--    border-color: $xtxColor;-->
<!--  }-->

<!--  &.disabled {-->
<!--    opacity: 0.6;-->
<!--    border-style: dashed;-->
<!--    cursor: not-allowed;-->
<!--  }-->
<!--}-->

<!--.goods-sku {-->
<!--  @media (max-width: 768px) {-->
<!--    dl {-->
<!--      flex-direction: column;-->
<!--      align-items: flex-start;-->

<!--      dt {-->
<!--        margin-bottom: 8px;-->
<!--      }-->
<!--    }-->
<!--  }-->
<!--  padding-left: 10px;-->
<!--  padding-top: 20px;-->

<!--  dl {-->
<!--    display: flex;-->
<!--    padding-bottom: 20px;-->
<!--    align-items: center;-->

<!--    dt {-->
<!--      width: 50px;-->
<!--      color: #999;-->
<!--    }-->

<!--    dd {-->
<!--      flex: 1;-->
<!--      color: #666;-->

<!--      > img {-->
<!--        width: 50px;-->
<!--        height: 50px;-->
<!--        margin-bottom: 4px;-->
<!--        @include sku-state-mixin;-->
<!--      }-->

<!--      > span {-->
<!--        display: inline-block;-->
<!--        height: 30px;-->
<!--        line-height: 28px;-->
<!--        padding: 0 20px;-->
<!--        margin-bottom: 4px;-->
<!--        @include sku-state-mixin;-->
<!--      }-->
<!--    }-->
<!--  }-->
<!--}-->
<!--</style>-->
